package com.fit.spring.boot.proxy.interceptor.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;

/**
 * 反射工具类
 * @author hcl
 *
 */
public class ReflectUtil {
	
	//********************************************************
	//  获取和执行Method、Field start
	//********************************************************
	
	/**
	 * 根据方法名称和方法参数类型获取Method对象
	 * @param clazz Class对象
	 * @param methodName 方法名称
	 * @param parameterTypes 参数类型集合
	 * @return
	 */
	public static Method getMethod(Class<?> clazz,String methodName,Class<?>... parameterTypes) throws NoSuchMethodException{
		Method result = null;
		if(clazz != null && methodName != null && !"".equals(methodName.trim())){
			try{
				result = clazz.getMethod(methodName, parameterTypes);
			}catch(NoSuchMethodException e){}
			if(result == null){
				result = clazz.getDeclaredMethod(methodName, parameterTypes);
			}
		}
		return  result;
	}

	//********************************************************
	//  反射获取注解 start,如果获取的是父类上的注解,那么这个注解必须加@Inherited
	//********************************************************
	

	/**
	 * 获取类和父类上指定的注解(不包含接口)
	 * 如果获取的是父类上的注解,那么这个注解必须加@Inherited
	 * @param clazz 需要获取注释的class类
	 * @param annotationClass 指定需要被获取的注释
	 * @return 
	 */
	public static <T extends Annotation> T getAnnotation(Class<?> clazz,Class<T> annotationClass){
		T result = null;
		if(clazz != null && annotationClass != null && clazz.isAnnotationPresent(annotationClass)){
			result = clazz.getAnnotation(annotationClass);
		}
		return result;
	}
	

	
	/**
	 * 获取实现了AccessibleObject接口对象上指定的注解
	 * AccessibleObject的子类有：Field(字段对象), Method(方法对象), Constructor(构造方法对象), ReflectPermission(反射操作的 Permission 类)
	 * @param obj 被获取注解的对象
	 * @param annotationClass 指定要被获取的注解类型
	 * @return
	 */
	public static <T extends Annotation> T getAnnotation(AccessibleObject obj,Class<T> annotationClass){
		T result = null;
		if(obj != null && annotationClass != null && obj.isAnnotationPresent(annotationClass)){
			result = obj.getAnnotation(annotationClass);
		}
		return result;
	}

	/**
	 * 获取Method上指定的注解(包含所有的父接口)
	 * 查找路径：方法上->类上->父接口方法上->父接口上->一直向上找
	 * @param clazz class类对象
	 * @param method 方法对象
	 * @param annotationClass 指定要被获取的注解类型
	 * @return
	 * @throws NoSuchMethodException 
	 */
	public static <T extends Annotation> T getMethodInterfacesAnnotation(Class<?> clazz,Method method,Class<T> annotationClass) throws NoSuchMethodException{
		T result = null;
		if(clazz != null && method != null && annotationClass != null){
			result =  getMethodInterfacesAnnotation(clazz,method.getName(), method.getParameterTypes(), annotationClass);
		}
		return result;
	}
	
	/**
	 * 获取Method上指定的注解(包含所有的父接口)
	 * 查找路径：方法上->类上->父接口方法上->父接口上->一直向上找
	 * @param clazz class类对象
	 * @param methodName 方法名称
	 * @param methodParameterTypes 参数类型数组
	 * @param annotationClass 指定要被获取的注解类型
	 * @return
	 * @throws NoSuchMethodException 
	 */
	private static <T extends Annotation> T getMethodInterfacesAnnotation(Class<?> clazz,String methodName,Class<?>[] methodParameterTypes,Class<T> annotationClass) throws NoSuchMethodException{
		T result = null;
		Method method = getMethod(clazz, methodName, methodParameterTypes);
		if(method != null){
			//从方法上获取
			result = getAnnotation(method, annotationClass);
			if(result == null){
				//从类上获取
				result = getAnnotation(clazz, annotationClass);
				if(result == null){
					//从接口中方法或接口类中获取
					Class<?>[] ins = clazz.getInterfaces();
					for(Class<?> in : ins){
						result = getMethodInterfacesAnnotation(in, methodName, methodParameterTypes, annotationClass);
						if(result != null){
							break;
						}
					}
				}
			}
		}
		return result;
	}
	
	//********************************************************
	//  反射获取注解 end,如果获取的是父类上的注解,那么这个注解必须加@Inherited
	//********************************************************
	
	
}
